//! 哈希操作修复功能单元测试
//! 
//! 测试修复后的哈希操作功能，包括：
//! - HSET/HGET/HDEL命令的正确实现
//! - 哈希键格式的修复 (_hash_:key:field)
//! - TYPE命令对哈希类型的正确识别
//! - 哈希字段的增删改查操作
//! - 空哈希的清理机制

use std::collections::HashMap;
use tokio::sync::RwLock;
use std::sync::Arc;

/// 模拟简化版存储，用于测试哈希操作
#[derive(Debug, Default)]
struct MockStorage {
    data: HashMap<String, String>,
}

impl MockStorage {
    fn new() -> Self {
        Self {
            data: HashMap::new(),
        }
    }
    
    /// 实现修复后的HSET逻辑
    fn hset(&mut self, key: &str, field: &str, value: &str) -> i32 {
        let hash_key = format!("_hash_:{}:{}", key, field);
        let marker_key = format!("_hash_:{}", key);
        
        // 检查字段是否已存在
        let was_new = !self.data.contains_key(&hash_key);
        
        // 存储哈希字段
        self.data.insert(hash_key, value.to_string());
        
        // 标记这是一个哈希表
        self.data.insert(marker_key, "hash".to_string());
        
        if was_new { 1 } else { 0 }
    }
    
    /// 实现修复后的HGET逻辑
    fn hget(&self, key: &str, field: &str) -> Option<String> {
        let hash_key = format!("_hash_:{}:{}", key, field);
        self.data.get(&hash_key).cloned()
    }
    
    /// 实现修复后的HDEL逻辑
    fn hdel(&mut self, key: &str, field: &str) -> i32 {
        let hash_key = format!("_hash_:{}:{}", key, field);
        let deleted = if self.data.remove(&hash_key).is_some() { 1 } else { 0 };
        
        // 检查是否需要清理哈希表标记
        let hash_prefix = format!("_hash_:{}:", key);
        let has_fields = self.data.keys().any(|k| k.starts_with(&hash_prefix));
        if !has_fields {
            let marker_key = format!("_hash_:{}", key);
            self.data.remove(&marker_key);
        }
        
        deleted
    }
    
    /// 实现修复后的TYPE逻辑
    fn get_type(&self, key: &str) -> String {
        let marker_key = format!("_hash_:{}", key);
        if self.data.contains_key(&marker_key) {
            "hash".to_string()
        } else if self.data.contains_key(key) {
            "string".to_string()
        } else {
            "none".to_string()
        }
    }
    
    /// 设置普通字符串键
    fn set(&mut self, key: &str, value: &str) {
        self.data.insert(key.to_string(), value.to_string());
    }
}

#[cfg(test)]
mod hash_operation_tests {
    use super::*;
    
    #[test]
    fn test_hset_new_field() {
        let mut storage = MockStorage::new();
        
        // 测试设置新字段
        let result = storage.hset("myhash", "field1", "value1");
        assert_eq!(result, 1, "设置新字段应该返回1");
        
        // 验证数据存储格式
        assert!(storage.data.contains_key("_hash_:myhash:field1"), "哈希字段应该以正确格式存储");
        assert!(storage.data.contains_key("_hash_:myhash"), "应该存在哈希标记");
        assert_eq!(storage.data.get("_hash_:myhash:field1"), Some(&"value1".to_string()));
    }
    
    #[test]
    fn test_hset_existing_field() {
        let mut storage = MockStorage::new();
        
        // 先设置一个字段
        storage.hset("myhash", "field1", "value1");
        
        // 更新现有字段
        let result = storage.hset("myhash", "field1", "new_value");
        assert_eq!(result, 0, "更新现有字段应该返回0");
        
        // 验证值已更新
        assert_eq!(storage.data.get("_hash_:myhash:field1"), Some(&"new_value".to_string()));
    }
    
    #[test]
    fn test_hget_existing_field() {
        let mut storage = MockStorage::new();
        
        // 设置字段
        storage.hset("myhash", "field1", "value1");
        
        // 获取字段
        let result = storage.hget("myhash", "field1");
        assert_eq!(result, Some("value1".to_string()), "应该能获取到正确的字段值");
    }
    
    #[test]
    fn test_hget_nonexistent_field() {
        let storage = MockStorage::new();
        
        // 获取不存在的字段
        let result = storage.hget("myhash", "nonexistent");
        assert_eq!(result, None, "获取不存在的字段应该返回None");
    }
    
    #[test]
    fn test_hdel_existing_field() {
        let mut storage = MockStorage::new();
        
        // 设置字段
        storage.hset("myhash", "field1", "value1");
        storage.hset("myhash", "field2", "value2");
        
        // 删除一个字段
        let result = storage.hdel("myhash", "field1");
        assert_eq!(result, 1, "删除存在的字段应该返回1");
        
        // 验证字段已删除
        assert_eq!(storage.hget("myhash", "field1"), None);
        
        // 验证其他字段仍存在
        assert_eq!(storage.hget("myhash", "field2"), Some("value2".to_string()));
        
        // 验证哈希标记仍存在（因为还有其他字段）
        assert!(storage.data.contains_key("_hash_:myhash"), "哈希标记应该仍然存在");
    }
    
    #[test]
    fn test_hdel_last_field_cleanup() {
        let mut storage = MockStorage::new();
        
        // 设置一个字段
        storage.hset("myhash", "field1", "value1");
        
        // 删除最后一个字段
        let result = storage.hdel("myhash", "field1");
        assert_eq!(result, 1, "删除存在的字段应该返回1");
        
        // 验证字段已删除
        assert_eq!(storage.hget("myhash", "field1"), None);
        
        // 验证哈希标记已清理
        assert!(!storage.data.contains_key("_hash_:myhash"), "删除最后一个字段后哈希标记应该被清理");
    }
    
    #[test]
    fn test_hdel_nonexistent_field() {
        let mut storage = MockStorage::new();
        
        // 删除不存在的字段
        let result = storage.hdel("myhash", "nonexistent");
        assert_eq!(result, 0, "删除不存在的字段应该返回0");
    }
    
    #[test]
    fn test_type_command_hash() {
        let mut storage = MockStorage::new();
        
        // 设置哈希字段
        storage.hset("myhash", "field1", "value1");
        
        // 检查类型
        let result = storage.get_type("myhash");
        assert_eq!(result, "hash", "哈希键的类型应该是hash");
    }
    
    #[test]
    fn test_type_command_string() {
        let mut storage = MockStorage::new();
        
        // 设置字符串键
        storage.set("mystring", "value");
        
        // 检查类型
        let result = storage.get_type("mystring");
        assert_eq!(result, "string", "字符串键的类型应该是string");
    }
    
    #[test]
    fn test_type_command_nonexistent() {
        let storage = MockStorage::new();
        
        // 检查不存在键的类型
        let result = storage.get_type("nonexistent");
        assert_eq!(result, "none", "不存在键的类型应该是none");
    }
    
    #[test]
    fn test_multiple_hashes() {
        let mut storage = MockStorage::new();
        
        // 创建多个哈希
        storage.hset("hash1", "field1", "value1");
        storage.hset("hash1", "field2", "value2");
        storage.hset("hash2", "field1", "value3");
        
        // 验证各自独立
        assert_eq!(storage.hget("hash1", "field1"), Some("value1".to_string()));
        assert_eq!(storage.hget("hash1", "field2"), Some("value2".to_string()));
        assert_eq!(storage.hget("hash2", "field1"), Some("value3".to_string()));
        assert_eq!(storage.hget("hash2", "field2"), None);
        
        // 验证类型识别
        assert_eq!(storage.get_type("hash1"), "hash");
        assert_eq!(storage.get_type("hash2"), "hash");
    }
    
    #[test]
    fn test_hash_field_with_special_characters() {
        let mut storage = MockStorage::new();
        
        // 测试包含特殊字符的字段名和值
        storage.hset("myhash", "field:with:colons", "value with spaces");
        storage.hset("myhash", "field_with_underscores", "value:with:colons");
        
        // 验证能正确存储和检索
        assert_eq!(storage.hget("myhash", "field:with:colons"), Some("value with spaces".to_string()));
        assert_eq!(storage.hget("myhash", "field_with_underscores"), Some("value:with:colons".to_string()));
    }
    
    #[test]
    fn test_hash_field_overwrite_and_type_consistency() {
        let mut storage = MockStorage::new();
        
        // 设置哈希字段
        storage.hset("mykey", "field1", "value1");
        assert_eq!(storage.get_type("mykey"), "hash");
        
        // 覆写字段
        storage.hset("mykey", "field1", "new_value");
        assert_eq!(storage.get_type("mykey"), "hash");
        assert_eq!(storage.hget("mykey", "field1"), Some("new_value".to_string()));
        
        // 添加更多字段
        storage.hset("mykey", "field2", "value2");
        assert_eq!(storage.get_type("mykey"), "hash");
        
        // 删除所有字段
        storage.hdel("mykey", "field1");
        storage.hdel("mykey", "field2");
        
        // 验证类型变为none
        assert_eq!(storage.get_type("mykey"), "none");
    }
}

#[cfg(test)]
mod hash_edge_cases_tests {
    use super::*;
    
    #[test]
    fn test_empty_field_name() {
        let mut storage = MockStorage::new();
        
        // 测试空字段名
        storage.hset("myhash", "", "value");
        assert_eq!(storage.hget("myhash", ""), Some("value".to_string()));
        assert_eq!(storage.get_type("myhash"), "hash");
    }
    
    #[test]
    fn test_empty_field_value() {
        let mut storage = MockStorage::new();
        
        // 测试空字段值
        storage.hset("myhash", "field", "");
        assert_eq!(storage.hget("myhash", "field"), Some("".to_string()));
        assert_eq!(storage.get_type("myhash"), "hash");
    }
    
    #[test]
    fn test_unicode_field_and_value() {
        let mut storage = MockStorage::new();
        
        // 测试Unicode字段名和值
        storage.hset("myhash", "字段名", "中文值");
        storage.hset("myhash", "🔑", "🏠");
        
        assert_eq!(storage.hget("myhash", "字段名"), Some("中文值".to_string()));
        assert_eq!(storage.hget("myhash", "🔑"), Some("🏠".to_string()));
    }
    
    #[test]
    fn test_large_number_of_fields() {
        let mut storage = MockStorage::new();
        
        // 测试大量字段
        for i in 0..1000 {
            storage.hset("myhash", &format!("field_{}", i), &format!("value_{}", i));
        }
        
        // 验证所有字段
        for i in 0..1000 {
            assert_eq!(
                storage.hget("myhash", &format!("field_{}", i)),
                Some(format!("value_{}", i))
            );
        }
        
        assert_eq!(storage.get_type("myhash"), "hash");
        
        // 删除一半字段
        for i in 0..500 {
            storage.hdel("myhash", &format!("field_{}", i));
        }
        
        // 验证剩余字段仍然存在
        for i in 500..1000 {
            assert_eq!(
                storage.hget("myhash", &format!("field_{}", i)),
                Some(format!("value_{}", i))
            );
        }
        
        assert_eq!(storage.get_type("myhash"), "hash");
    }
}